{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The flexible interface\n",
    "\n",
    "In the previous tutorial, we have demonstrated how `sbi` can be used to run simulation-based inference with just a single line of code.\n",
    "\n",
    "In addition to this simple interface, `sbi` also provides a **flexible interface** which provides several additional features implemented in `sbi`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note, you can find the original version of this notebook at [https://github.com/sbi-dev/sbi/blob/main/tutorials/02_flexible_interface.ipynb](https://github.com/sbi-dev/sbi/blob/main/tutorials/02_flexible_interface.ipynb) in the `sbi` repository."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Features\n",
    "\n",
    "The flexible interface offers the following features (and many more):\n",
    "\n",
    "- performing sequential posterior estimation by focusing on a particular observation over multiple rounds. This can decrease the number of simulations one has to run, but the inference procedure is no longer amortized ([tutorial](https://sbi-dev.github.io/sbi/tutorial/03_multiround_inference/)).    \n",
    "- specify your own density estimator, or change hyperparameters of existing ones (e.g. number of hidden units for [NSF](https://arxiv.org/abs/1906.04032)) ([tutorial](https://www.mackelab.org/sbi/tutorial/04_density_estimators/)).    \n",
    "- use an `embedding_net` to learn summary features from high-dimensional simulation outputs ([tutorial](https://www.mackelab.org/sbi/tutorial/05_embedding_net/)).  \n",
    "- provide presimulated data  \n",
    "- choose between different methods to sample from the posterior.  \n",
    "- use calibration kernels as proposed by [Lueckmann, Goncalves et al. 2017](https://arxiv.org/abs/1711.01861)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Main syntax"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```Python\n",
    "from sbi.inference import SNPE, prepare_for_sbi, simulate_for_sbi\n",
    "\n",
    "simulator, prior = prepare_for_sbi(simulator, prior)\n",
    "inference = SNPE(prior)\n",
    "\n",
    "theta, x = simulate_for_sbi(simulator, proposal=prior, num_simulations=1000)\n",
    "density_estimator = inference.append_simulations(theta, x).train()\n",
    "posterior = inference.build_posterior(density_estimator)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Linear Gaussian example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will show an example of how we can use the flexible interface to infer the posterior for an example with a Gaussian likelihood (same example as before). First, we import the inference method we want to use (`SNPE`, `SNLE`, or `SNRE`) and other helper functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "\n",
    "from sbi.inference import SNPE, prepare_for_sbi, simulate_for_sbi\n",
    "from sbi.utils.get_nn_models import posterior_nn\n",
    "from sbi import utils as utils\n",
    "from sbi import analysis as analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we define the prior and simulator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_dim = 3\n",
    "prior = utils.BoxUniform(low=-2 * torch.ones(num_dim), high=2 * torch.ones(num_dim))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linear_gaussian(theta):\n",
    "    return theta + 1.0 + torch.randn_like(theta) * 0.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the flexible interface, you have to ensure that your simulator and prior adhere the requirements of `sbi`. You can do so with the `prepare_for_sbi()` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "simulator, prior = prepare_for_sbi(linear_gaussian, prior)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, we instantiate the inference object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "inference = SNPE(prior=prior)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we run simulations. You can do so either by yourself by sampling from the prior and running the simulator (e.g. on a compute cluster), or you can use a helper function provided by `sbi` called `simulate_for_sbi`. This function allows to parallelize your code with `joblib`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "66d28cf9f1304ca7838576033dc09099",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Running 2000 simulations.:   0%|          | 0/2000 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "theta, x = simulate_for_sbi(simulator, proposal=prior, num_simulations=2000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We then pass the simulated data to the inference object. `theta` and `x` should both be a `torch.Tensor` of type `float32`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "inference = inference.append_simulations(theta, x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we train the neural density estimator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Neural network successfully converged after 73 epochs."
     ]
    }
   ],
   "source": [
    "density_estimator = inference.train()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lastly, we can use this density estimator to build the posterior:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "posterior = inference.build_posterior(density_estimator)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once we have obtained the posterior, we can `.sample()`, `.log_prob()`, or `.pairplot()` in the same way as for the simple interface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_o = torch.zeros(3,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "037b102711844d3fbc63575522a65338",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Drawing 10000 posterior samples:   0%|          | 0/10000 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 360x360 with 9 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "posterior_samples = posterior.sample((10000,), x=x_o)\n",
    "\n",
    "# plot posterior samples\n",
    "_ = analysis.pairplot(\n",
    "    posterior_samples, limits=[[-2, 2], [-2, 2], [-2, 2]], figsize=(5, 5)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can always print the posterior to know how it was trained:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Posterior conditional density p(θ|x) of type DirectPosterior. It samples the posterior network and rejects samples that\n",
      "            lie outside of the prior bounds.\n"
     ]
    }
   ],
   "source": [
    "print(posterior)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
